﻿
namespace TADF.Com.Alpha.Core.Module
{
    #region Imports
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Xml;
    #endregion

    public class ModuleManager
    {
        private static ModuleManager _ins = new ModuleManager();

        private string _webName = "";
        private string _locale = "";
        private string _failedPage = "";
        private string[] _reqMapping = new string[0];

        private IDictionary<string, AspectModule> _aspectModulesMap = new Dictionary<string, AspectModule>();
        private IDictionary<string, AppModule> _appModulesMap = new Dictionary<string, AppModule>();

        //private Map<String, SysMenuItem> _menuItemMap = new LinkedHashMap<String, SysMenuItem>();

        private string _basePath;

        private void ModuleManger()
        {
        }

        public static ModuleManager GetInstance()
        {
            return _ins;
        }

        private void log()
        {
            _aspectModulesMap.Add("___@@@XXXEEEE&&", new Test());
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="strm">配置文件流</param>
        public void Init(Stream strm)
        {
            try
            {
                log();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            XmlDocument doc = new XmlDocument();
            doc.Load(strm);
            strm.Close();

            XmlNode node = doc.SelectSingleNode("//alpha-module/web-app-name");
            if (node != null)
                _webName = node.InnerText.ToString();
            node = doc.SelectSingleNode("//alpha-module/locale");
            if (node != null)
                _locale = node.InnerText.ToString();
            node = doc.SelectSingleNode("//alpha-module/failed-page");
            if (node != null)
                _failedPage = node.InnerText.ToString();
            node = doc.SelectSingleNode("//alpha-module/req-mapping");
            if (node != null)
            {
                String[] mapping = node.InnerText.ToString().Split(',');
                for (int i = 0; i < mapping.Length; ++i)
                {
                    mapping[i] = mapping[i].Trim();
                }
                _reqMapping = mapping;
            }

            //先创建所有同级对象。以保证作模块关联的时候对象存在。
            XmlNodeList aspList = doc.SelectNodes("//alpha-module/aspect-module");
            if (aspList != null && aspList.Count > 0)
            {
                foreach (XmlNode n in aspList)
                {
                    AspectModule module = (AspectModule)NewAlphaModule(n, typeof(BaseAspectModule));
                    _aspectModulesMap.Add(module.Name, module);
                }
            }

            XmlNodeList appList = doc.SelectNodes("//alpha-module/app-module");
            if (appList != null && appList.Count > 0)
            {
                foreach (XmlNode n in appList)
                {
                    AppModule module = (AppModule)NewAlphaModule(n, typeof(BaseAppModule));
                    _appModulesMap.Add(module.Name, module);
                }
            }


            IDictionary<string, AlphaModule> moduleMap = new Dictionary<string, AlphaModule>();
            //moduleMap.Add(_aspectModulesMap);
            //moduleMap.Add(_appModulesMap);

            ParseAspectModule(aspList, moduleMap);
            ParseAppModule(appList, moduleMap);
        }

        private void ParseAspectModule(XmlNodeList nodes, IDictionary<string, AlphaModule> moduleMap)
        {
            if (nodes == null || nodes.Count == 0)
                return;

            XmlElement xe;
            AlphaModule module;           

            foreach (XmlNode n in nodes)
            {
                xe = (XmlElement)n;
                moduleMap.TryGetValue(xe.GetAttribute("name").ToString(), out module);
               
                //先读取独立配置文件
                string clazz = xe.GetAttribute("class").ToString();
                StreamReader strm = GetModuleFileInputStream(clazz);
                if (strm != null)
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(strm);
                    strm.Close();
                    InitAspectModule((AspectModule)module, doc.SelectSingleNode("//aspect-module"), moduleMap);
                }

                InitAspectModule((AspectModule)module, n, moduleMap);
            }
        }

        private void ParseAppModule(XmlNodeList nodes, IDictionary<String, AlphaModule> moduleMap)
        {
            if (nodes == null || nodes.Count == 0)
                return;

            XmlElement xe;
            AlphaModule module;
            foreach (XmlNode n in nodes)
            {
                xe = (XmlElement)n;
                moduleMap.TryGetValue(xe.GetAttribute("name").ToString(),out module);
                //先读取独立配置文件
                string clazz = xe.GetAttribute("class").ToString();
                StreamReader strm = GetModuleFileInputStream(clazz);
                if (strm != null)
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(strm);
                    strm.Close();
                    InitAppModule((AppModule)module, doc.SelectSingleNode("//App-module"), moduleMap);
                }

                InitAppModule((AppModule)module, n, moduleMap);
            }
        }

        private void InitAppModule(AppModule module, XmlNode node, IDictionary<String, AlphaModule> moduleMap)
        {
            XmlNode loc = node.SelectSingleNode("./locale");
            if (loc != null)
                module.Locale = loc.InnerText.ToString();
            XmlNode pd = node.SelectSingleNode("./page-path");
            if (pd != null)
                module.PagePath = pd.InnerText.ToString();
            XmlNode fp = node.SelectSingleNode("./failed-page");
            if (fp != null)
                module.FailedPage = fp.InnerText.ToString();


            XmlNodeList actions = node.SelectNodes("./actions/*");
            if (actions.Count > 0)
            {
                IDictionary<String, Object> am = new Dictionary<String, Object>();
                foreach (XmlNode a in actions)
                {
                    XmlElement xe = (XmlElement)a;
                    Object obj = System.Activator.CreateInstance(Type.GetType(xe.GetAttribute("class").ToString()));
                    String iref = xe.GetAttribute("@context-module").ToString();
                    if (iref != null && iref.Length > 0)
                    {
                        //BeanUtils.setProperty(obj, iref, module);
                    }
                    am.Add(a.Name, obj);
                }
                module.Actions = am;
            }
            module.OnInit();

            //解析子模块。
            XmlNode childModule = node.SelectSingleNode("./child-module");
            if (childModule != null)
            {
                XmlNodeList aspList = childModule.SelectNodes("./aspect-module");
                if (aspList != null && aspList.Count > 0)
                {
                    foreach (XmlNode n in aspList)
                    {
                        AspectModule m = (AspectModule)NewAlphaModule(n, typeof(BaseAspectModule));
                        m.ParentModule = module;
                        module._aspectChild.Add(m.Name, m);
                    }
                }
                XmlNodeList appList = childModule.SelectNodes("./app-module");

                if (appList != null && appList.Count > 0)
                {
                    foreach (XmlNode n in appList)
                    {
                        AppModule m = (AppModule)NewAlphaModule(n, typeof(BaseAppModule));
                        m.ParentModule = module;
                        module._appChild.Add(m.Name, m);
                    }
                }
                IDictionary<String, AlphaModule> childModuleMap = new Dictionary<String, AlphaModule>();

                childModuleMap.Add(module._aspectChild);
                childModuleMap.Add(module._appChild);

                ParseAspectModule(aspList, childModuleMap);
                ParseAppModule(appList, childModuleMap);
            }
        }

        private void InitAspectModule(AspectModule module, XmlNode node, IDictionary<string, AlphaModule> moduleMap)
        {
            XmlNode loc = node.SelectSingleNode("./locale");
            if (loc != null)
                module.Locale = loc.InnerText.ToString();

            XmlNodeList actions = node.SelectNodes("./actions/*");
            if (actions.Count > 0)
            {
                Dictionary<String, Object> am = new Dictionary<String, Object>();
                XmlElement xe;

                foreach (XmlNode a in actions)
                {
                    xe = (XmlElement)a;
                    Object obj = System.Activator.CreateInstance(Type.GetType(xe.GetAttribute("class").ToString()));
                    String iref = xe.GetAttribute("@context-module").ToString();
                    if (iref != null && iref.Length > 0)
                    {
                        //BeanUtils.setProperty(obj, iref, module);
                    }
                    am.Add(a.Name, obj);
                }
                module.Actions = am;
            }
            module.OnInit();
        }


        private AlphaModule NewAlphaModule(XmlNode node, Type defaultClazz)
        {
            Type clazz = null;

            XmlElement xe = (XmlElement)node;
            try
            {
                clazz = Type.GetType(xe.GetAttribute("class").ToString());
            }
            catch
            {
                clazz = defaultClazz;
            }
            AlphaModule module = (AlphaModule)System.Activator.CreateInstance(clazz);
            module.Name = xe.GetAttribute("name").ToString();

            return module;
        }

        private StreamReader GetModuleFileInputStream(string clazz)
        {
            string file = "/" + clazz.Substring(0, clazz.LastIndexOf(".") + 1).ToString().Replace(".", "/") + "module.xml";
            return (new StreamReader(file, Encoding.Default));
        }

        public string WebName
        {
            get { return _webName; }
            set { _webName = value; }
        }

        public string Locale
        {
            get { return _locale; }
        }

        public AlphaModule GetModule(String name)
        {
            if (_aspectModulesMap.ContainsKey(name))
                return _aspectModulesMap.Values(name);
            else if (_appModulesMap.ContainsKey(name))
                return _appModulesMap.Keys(name);
            return null;
        }

        public AppModule GetAppModule(String name)
        {
            if (_appModulesMap.ContainsKey(name))
                return _appModulesMap.Keys(name);

            String[] m = name.Split("\\.");
            AppModule p = _appModulesMap.Keys(m[0]);
            for (int i = 1; i < m.Length; ++i)
            {
                p = (AppModule)p.GetAppChildModule(m[i]);
            }
            return p;
        }

        public object[] GetAspectModules()
        {
            object[] obj;
             _aspectModulesMap.Values.CopyTo(obj,0);
             return obj;
        }

        public AspectModule[] GetAllAspectModules()
        {
            List<AspectModule> list = new ArrayList();

            list.Ad(_aspectModulesMap.Values);
            rtAspectModules(list, GetAppModules());

            return list.ToArray(new AspectModule[list.Count]);
        }

        private void rtAspectModules(List<AspectModule> list, AppModule[] appModules)
        {
            foreach (AppModule m in appModules)
            {
                foreach (AspectModule am in m.GetChildAspectModules())
                {
                    list.add(am);
                }
            }
            foreach (AppModule m in appModules)
            {
                rtAspectModules(list, m.GetAppChildModule());
            }
        }

        public AppModule[] GetAppModules()
        {
            return _appModulesMap.Values.ToString().ToCharArray(new AppModule[_aspectModulesMap.Count]);
        }

        public AlphaModule GetContextModule(Object action)
        {
            return null;
        }

        public String[] GetReqMapping()
        {
            return _reqMapping;
        }

        //public SysMenuItem GetSysMenuItem(String id)
        //{
        //    return _menuItemMap.get(id);
        //}

        //public SysMenuItem[] getAllSysMenuItem()
        //{
        //    return menuItemMap.values().toArray(new SysMenuItem[menuItemMap.size()]);
        //}

        public String GetFailedPage()
        {
            return _failedPage;
        }

        public String GetFailedPage(AppModule module)
        {
            if (module.FailedPage != null && module.FailedPage.Length > 0)
                return module.FailedPage();
            return _failedPage;
        }

        public String GetBasePath
        {
            get { return _basePath; }
            set { _basePath = value; }
        }
    }
}
